/**
 * Copyright (c) 2018, 西安星沙网络科技-版权所有
 *
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.gnu.org/licenses/lgpl-3.0.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.waleychain.exchange.service.impl.wallet.utils;

import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.azazar.bitcoin.jsonrpcclient.Bitcoin;
import com.azazar.bitcoin.jsonrpcclient.Bitcoin.AddressValidationResult;
import com.azazar.bitcoin.jsonrpcclient.Bitcoin.Info;
import com.azazar.bitcoin.jsonrpcclient.BitcoinAcceptor;
import com.azazar.bitcoin.jsonrpcclient.BitcoinException;
import com.azazar.bitcoin.jsonrpcclient.BitcoinJSONRPCClient;
import com.jsuportframework.util.JSUtils;

import cn.waleychain.exchange.core.logger.LoggerHelper;
import cn.waleychain.exchange.core.utils.CalendarUtils;
import cn.waleychain.exchange.core.utils.StringUtils;
import cn.waleychain.exchange.feign.CoinServiceFeign;
import cn.waleychain.exchange.feign.UserServiceFeign;
import cn.waleychain.exchange.model.CoinInfo;
import cn.waleychain.exchange.model.WalletCollectTask;
import cn.waleychain.exchange.service.impl.wallet.listener.ReceiveCoinListener;
import cn.waleychain.exchange.service.wallet.CoinWalletService;

@Service
public class DefaultCoinClient {

	private static final Logger mLog = LoggerFactory.getLogger(DefaultCoinClient.class);
	
	@Autowired
	private UserServiceFeign userFeign;
	
	@Autowired
	private CoinWalletService coinWalletService;
	
	@Autowired
	private CoinServiceFeign coinFeign;
	
	public BigDecimal getBalance(CoinInfo tradeCoin) {
        return this.getBalance(tradeCoin, (String)null);
    }

    public BigDecimal getBalance(CoinInfo tradeCoin, String addr) {
        try {
            Bitcoin client = getCoinClient(tradeCoin);
            return JSUtils.ifStringEmpty(addr) ? BigDecimal.valueOf(client.getBalance()) : BigDecimal.valueOf(client.getBalance(addr));
        } catch (Exception e) {
            LoggerHelper.printLogErrorNotThrows(mLog, e, "获取余额失败");
            return new BigDecimal("-99");
        }
    }
    
    public boolean isValidAddress(CoinInfo tradeCoin, String addr) {
        try {
            Bitcoin client = getCoinClient(tradeCoin);
            AddressValidationResult validate = client.validateAddress(addr);
            if (!validate.isValid()) {
                throw new Exception(addr + "不是一个有效的钱包地址！");
            } else {
                return true;
            }
        } catch (Exception e) {
        	LoggerHelper.printLogErrorNotThrows(mLog, e, "验证地址");
            return false;
        }
    }
	
    public String sendToAddress(CoinInfo tradeCoin, Long userId, String to, BigDecimal amount) throws Exception {
        try {
            Bitcoin client = getCoinClient(tradeCoin);
            String sender = client.sendToAddress(to, amount.doubleValue());
            if (sender != null && sender.indexOf("status") != -1) {
            	LoggerHelper.printLogErrorNotThrows(mLog, null, "Send transaction error：" + sender);
                throw new Exception("Send transaction error:" + sender);
            } else {
                return sender;
            }
        } catch (Exception var7) {
            throw new Exception(var7);
        }
    }
    
    public String sendToCenter(CoinInfo tradeCoin, Long userId, String to, BigDecimal amount) throws Exception {
        return this.sendToAddress(tradeCoin, userId, to, amount);
    }
    
    public void addCollectTask(CoinInfo tradeCoin, Long userId, BigDecimal amount) throws Exception {
        if (!JSUtils.ifStringEmpty("")) {
            BigDecimal transferAmount = amount.multiply(BigDecimal.valueOf(0.95D));
            if (BigDecimal.ZERO.compareTo(transferAmount) >= 0) {
                throw new Exception("Transfer amount is zero!");
            } else {
            	 WalletCollectTask task = new WalletCollectTask();
                 task.setCoinId(tradeCoin.getCoinId());
                 task.setFromUser(userId);
                 task.setToAddr("");
                 task.setAmount(transferAmount);
                 task.setExecTime(CalendarUtils.addMinute(new Date(), 30));
                 
                 this.coinWalletService.createWalletCollectTask(task);
            }
        }
    }
    
	public void refreshAcceptor(CoinInfo coin) throws Exception {
        if (coin != null) {
            Bitcoin client = null;

            try {
                client = getCoinClient(coin);
            } catch (Exception var6) {
                LoggerHelper.printLogErrorNotThrows(mLog, var6, var6.getMessage());
                return;
            }

            BitcoinAcceptor acceptor = new BitcoinAcceptor(client);
            if (StringUtils.isNotBlank(coin.getLastblock())) {
                try {
                    acceptor.setLastBlock(coin.getLastblock());
                } catch (BitcoinException var5) {
                    var5.printStackTrace();
                    return;
                }
            }

            acceptor.addListener(new ReceiveCoinListener(coin.getCoinId(), coin.getName(), client, userFeign, coinWalletService, coinFeign));
            WalletAcceptorUtil.instance.upAcceptor(coin.getCoinId(), acceptor);
        }
    }
	
	public static Bitcoin getCoinClient(CoinInfo coin) throws Exception {
		
        if (coin != null && StringUtils.isNotBlank(coin.getRpcUser()) && StringUtils.isNotBlank(coin.getRpcPassword()) && 
        		StringUtils.isNotBlank(coin.getRpcIp())) {
        	
            LoggerHelper.printLogInfo(mLog, "钱包开始初始化：" + coin.getName());
            String rpcUrl = "http://" + coin.getRpcUser() + ":" + coin.getRpcPassword() + "@" + coin.getRpcIp() + ":" + coin.getRpcPort();
            BitcoinJSONRPCClient client = null;
            try {
                client = new BitcoinJSONRPCClient(new URL(rpcUrl));
            } catch (MalformedURLException var4) {
                throw new Exception(var4);
            }
            Info info = client.getInfo();
            if (info != null && StringUtils.isEmpty(info.errors())) {
            	
                LoggerHelper.printLogInfo(mLog, "钱包初始化结束：" + coin.getName());
                return client;
            } else {
                throw new NullPointerException("Get CoinClient Error");
            }
        } else {
            throw new IllegalArgumentException("RPC no setting");
        }
    }
	
	public int getTransactionConfirmed(CoinInfo tradeCoin, String txid) {
        try {
            Bitcoin client = getCoinClient(tradeCoin);
            return client.getTransaction(txid).confirmations();
        } catch (Exception e) {
        	LoggerHelper.printLogErrorNotThrows(mLog, e, e.getMessage());
            return 0;
        }
    }
}
